/*
 * File name: PluginManager.java
 * 
 * Description: 
 *
 * Author: Theobald_wu, contact with wuqizhi@tydtech.com
 * 
 * Date: 2015-3-12   
 * 
 * Copyright (C) 2015 Zhouyou Network Technology Co.,Ltd.
 * 
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.freeme.pluginmanager;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.util.Log;
import dalvik.system.PathClassLoader;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import android.text.TextUtils;

public class PluginManager {
    private static final String TAG = "[FREEME]PluginManager";
    private Context mContext;
    private PackageManager mPackageMgr;
    private String mShareUserId;
    private PluginListener mListener;
    private List<Plugin> mPlugins = new ArrayList<Plugin>();

    public PluginManager(Context context, PluginListener listener) {
        mContext = context;
        mListener = listener;
        mPackageMgr = mContext.getPackageManager();
        try {
            mShareUserId = mPackageMgr.getPackageInfo(mContext.getPackageName(), 0).sharedUserId;
        } catch (Exception e) {
            e.printStackTrace();
        }

        // register intent receivers
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_PACKAGE_ADDED);
        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
        // filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
        filter.addDataScheme("package");
        mContext.registerReceiver(mBroadcastReceiver, filter);

        // scanning all context's plugins
        scanPlugins();
    }

    public void notifyOrientationChanged(int orientation) {
        for (Plugin plugin : mPlugins) {
            if (plugin.getInstance() != null) {
                plugin.getInstance().notifyOrientationChanged(orientation);
            }
        }
    }

    public void release() {
        mContext.unregisterReceiver(mBroadcastReceiver);

        // release plugin
        for (Plugin plugin : mPlugins) {
            if (plugin.getInstance() != null) {
                plugin.getInstance().release();
            }
        }
        mPackageMgr = null;
    }

    @Deprecated
    public static Object createPluginObject(Context context, String plugin) {
        PackageManager pkgMgr = context.getPackageManager();
        String shareUserId = "";
        List<PackageInfo> pkgInfos = null;
        try {
            pkgInfos = pkgMgr
                .getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES);
            shareUserId = pkgMgr.getPackageInfo(context.getPackageName(), 0).sharedUserId;
        } catch (Exception e) {
            return null;
        }

        for (PackageInfo pkgInfo : pkgInfos) {
            if (shareUserId.equals(pkgInfo.sharedUserId)
                    && !context.getPackageName().equals(pkgInfo.packageName)) {
                Log.i(TAG, "package name = " + pkgInfo.packageName);
                // Get all activities by package name
                PackageInfo finalPkgInfo = null;
                try {
                    finalPkgInfo = pkgMgr.getPackageInfo(pkgInfo.packageName,
                            PackageManager.GET_ACTIVITIES);
                } catch (Exception e) {
                    continue;
                }

                for (ActivityInfo activityInfo : finalPkgInfo.activities) {
                    ClassLoader cl = new PathClassLoader(activityInfo.applicationInfo.sourceDir,
                            context.getClassLoader());
                    try {
                        Log.i(TAG, "activity name = " + activityInfo.name);
                        Constructor constructor = cl.loadClass(activityInfo.name).getConstructor(
                                new Class[] {
                                        Context.class, String.class
                                });
                        Object obj = constructor.newInstance(new Object[] {
                                context, pkgInfo.packageName
                        });
                        Class[] superInterfaces = obj.getClass().getInterfaces();
                        for (Class superName : superInterfaces) {
                            Log.i(TAG, "superName = " + superName.getName());
                            if (plugin.equals(superName.getName())) {
                                return obj;
                            }
                        }
                    } catch (Exception e) {

                    }
                }
            }
        }

        return null;
    }

    private void scanPlugins() {
        List<PackageInfo> pkgInfos = null;
        try {
            pkgInfos = mPackageMgr
                .getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES);
        } catch (Exception e) {
            return;
        }
        mPlugins.clear();
        for (PackageInfo pkgInfo : pkgInfos) {
            if (mShareUserId.equals(pkgInfo.sharedUserId)
                    && !mContext.getPackageName().equals(pkgInfo.packageName)) {
                Log.i(TAG, "package name = " + pkgInfo.packageName);
                // Get all activities by package name
                PackageInfo finalPkgInfo = null;
                try {
                    finalPkgInfo = mPackageMgr.getPackageInfo(pkgInfo.packageName,
                            PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA);
                } catch (Exception e) {
                    continue;
                }
                if (finalPkgInfo == null || finalPkgInfo.activities == null) {
                    continue;
                }
                for (ActivityInfo activityInfo : finalPkgInfo.activities) {
                    Plugin plugin = new Plugin(mContext, pkgInfo.packageName, activityInfo);
                    // add by tyd yzhu 20151218,others activity of largemode
                    // which is not a plugin
                    if (plugin.getType() != null) {
                        mPlugins.add(plugin);
                    }
                    // end
                }
            }
        }

        if (mListener != null) {
            mListener.onRefreshPlugins(mPlugins, mPlugins, null);
        }
    }

    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            Log.i(TAG, "onReceive(): action = " + action);
            if (mPackageMgr == null) {
                return;
            }
            if (Intent.ACTION_PACKAGE_ADDED.equals(action)
                    || Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
                String packageName = intent.getData().getSchemeSpecificPart();
                Log.i(TAG, "onReceive(): packageName = " + packageName);
                if (packageName == null || packageName.length() == 0) {
                    // they sent us a bad intent
                    return;
                }

                if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
                    PackageInfo packageInfo = null;
                    try {
                        packageInfo = mPackageMgr.getPackageInfo(packageName,
                                PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA);
                    } catch (Exception e) {
                        e.printStackTrace();
                        return;
                    }

                    Log.i(TAG, "onReceive(): packageInfo.sharedUserId = "
                            + packageInfo.sharedUserId);
                    if (TextUtils.isEmpty(packageInfo.sharedUserId)
                            || !packageInfo.sharedUserId.equals(mShareUserId)
                            || mContext.getPackageName().equals(packageName)) {
                        return;
                    }

                    // package added
                    List<Plugin> added = new ArrayList<Plugin>(packageInfo.activities.length);
                    for (ActivityInfo activityInfo : packageInfo.activities) {
                        Plugin plugin = new Plugin(mContext, packageName, activityInfo);
                        mPlugins.add(plugin);
                        added.add(plugin);
                    }

                    if (mListener != null) {
                        mListener.onRefreshPlugins(mPlugins, added, null);
                    }
                } else {
                    // package removed
                    List<Plugin> removed = new ArrayList<Plugin>(mPlugins.size());
                    Iterator<Plugin> iterator = mPlugins.iterator();
                    Log.i(TAG, "onReceive(): plugins size = " + mPlugins.size());
                    while (iterator.hasNext()) {
                        Plugin plugin = iterator.next();
                        if (packageName.equals(plugin.getPackageName())) {
                            removed.add(plugin);
                            iterator.remove();
                        }
                    }
                    Log.i(TAG, "onReceive(): after removed, plugins size = " + mPlugins.size());

                    if (mListener != null) {
                        mListener.onRefreshPlugins(mPlugins, null, removed);
                    }
                }
            }
        }
    };
}
